<?php
/**
 *
 *
 *
 */
class Yz_Action_SelectNeighbors
    extends Yz_Action_Select
{

    /**
     *  @var int ?
     */
    protected $itemId;
    protected $order = 'id ASC';

    /**
     *  @param int id > 0
     *  @return this
     */
    public function setItem(Yz_Item_Interface $item)
    {
        debug();
        assert('$item->id > 0');
        $this->itemId = $item->id;
        $this->count = null;
        return $this;
    }


    /** Execute the action
     *  @return this
     */
    public function perform()
    {
        try {
            parent::perform();
            assert('$this->count == 1 or $this->count == 2');
            $neighbors = $this->statement->fetchAll()->toArray(); // Yz_Array
            $neighbors = $this->_sort($neighbors);
        } catch (NotFoundError $ex) {
            $neighbors = array(null, null);
        }
        $this->result = $neighbors;
        return $this;
    }


    /** Fetch the 'Previous' item
     *  @return this|false
     */
    public function fetch()
    {
        if (null === $this->count)
            $this->perform();
        assert('is_array($this->result)');
        $values = $this->result[0];
        debug("Previous item: " . ($values ? $values->id : 'NONE'));
        if (! $values)
            return false;
        $this->__dict__ = $values->toArray();
        return $this;
    }

    /** Fetch the 'Next' item
     *  @return this|false
     */
    public function fetchNext()
    {
        if (null === $this->count)
            $this->perform();
        assert('is_array($this->result)');
        $values = $this->result[1];
        debug("Next item: " . ($values ? $values->id : 'NONE'));
        if (! $values)
            return false;
        $this->__dict__ = $values->toArray();
        return $this;
    }

    /************************************
     *        Protected methods         *
     ************************************/


    /**
     *  Build the common part of the SQL statement
     *  @abstract
     *  @return Yz_SQL_Statement
     */
    protected function buildStatement()
    {
        $this->inspectModel();
        $fields = $this->fields;
        $sqlPrev = Yz_SQL_Statement_Select::create()
            ->select($fields)
            ->from($this->tables)
        ;
        $sqlNext = Yz_SQL_Statement_Select::create()
            ->select($fields)
            ->from($this->tables)
        ;
        $source = key($this->tables);
        $sqlNext
        // create two SQL Selects
            ->where("{$source}.id > :_id")
            ->orderBy("{$source}.id ASC")
            ->limit(1)
        ;
        $sqlPrev
            ->where("{$source}.id < :_id")
            ->orderBy("{$source}.id DESC")
            ->limit(1)
        ;
        $union = Yz_SQL_Statement_Union::create()
            ->union($sqlPrev, $sqlNext)
            #->orderBy($this->order)
        ;
        return $union;
    }


    /**
     *  Apply the arguments to the SQL statement
     *  @param Yz_SQL_Statement $sql
     *  @return this
     */
    protected function applyArguments(Yz_SQL_Statement $sql)
    {
        debug();
        // NOTE: item id can change between setItem and applyArguments
        $sql->bind('_id', $this->itemId) ;
        return $this;
    }


    /**
     *  @param
     *  @return
     */
    protected function _sort(array $neighbors)
    {
        debug();
        assert('!!$neighbors');
        $i0 = current($neighbors); // first item
        $i1 = end($neighbors); // last item

        if ($i0->id < $this->itemId) { // first item is the previous neighbor
            $p = 0;
            $n = 1;
        } else {
            $p = 1;
            $n = 0;
        }
        $out = array();
        $out[$p] = $i0;
        $out[$n] = $i0 === $i1 ? null : $i1;
        return $out;
    }


}
